package com.dxy.netty.tcppackagesolve;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.nio.charset.StandardCharsets;

/**
 * @Description "头部包含数据包长度"方式解决粘包拆包问题-netty客户端处理器
 * @Author dangxianyue
 * @Date 2023/1/8 22:13
 */
public class ProtocolNettyClientHandler extends SimpleChannelInboundHandler<ProtocolMessage> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ProtocolMessage msg) throws Exception {
        System.out.println(new String(msg.getContent(), StandardCharsets.UTF_8));
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 发送100条数据到服务器
        for (int i = 1; i <= 100; i++) {
            byte[] body = ("hello_server_" + i + " ").getBytes(StandardCharsets.UTF_8);
            // 创建协议包对象
            ProtocolMessage message = new ProtocolMessage();
            message.setContent(body);
            message.setLength(body.length);
            // 发送
            ctx.writeAndFlush(message);
        }
    }

    // 当发送100条数据时，会报错，发送10条数据时正常
    // Caused by: java.lang.IndexOutOfBoundsException: readerIndex(1019) + length(1751477356) exceeds writerIndex(1024): PooledUnsafeDirectByteBuf(ridx: 1019, widx: 1024, cap: 1024)
    // 数据包的长度为1751477356，而ByteToMessageDecoder只处理到了512，数据包的大小超过​512b​的时候就会抛出异常了
    // 配合解码器DelimiterBasedFrameDecoder一起使用，在数据包的末尾使用换行符\r\n表示本次数据包已经结束，
    // 当DelimiterBasedFrameDecoder把数据切割之后，再使用ByteToMessageDecoder实现decode方法把数据流转换为ProtocolMessage对象。
    // 参考1：netty 数据包黏包拆包处理器使用及遇到的问题
    // https://blog.csdn.net/u011035407/article/details/80454511
    // 参考2：20-Netty TCP 粘包和拆包及解决方案
    // https://blog.51cto.com/u_15196075/5055760


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
